import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import type { RootState } from '@/types/store'
import { usePersistFn } from 'ahooks'

/**
 * 进入页面时，获取数据
 * @param action 获取数据的 action 函数
 * @param stateName 获取状态的名称，对应 RootState 中某个状态名称
 * @param afterAction 回调函数，表示在 action 完成后，执行某个操作
 * @return 要获取的状态
 */
export const useInitialState = <StateName extends keyof RootState>(
  action: () => void,
  stateName: StateName,
  afterAction = () => {}
): RootState[StateName] => {
  const dispatch = useDispatch()
  const state = useSelector((state: RootState) => state[stateName])
  // 对于 useRef 来说，参数只会在第一次组件渲染时生效，类似 useState 的参数
  const persistAction = usePersistFn(action)
  // 创建用来处理 afterAction 的 ref 对象，来避免递归发送请求
  const persistAfterAction = usePersistFn(afterAction)

  // 注意：useEffect 无法检测到 usePersistFn 内部是否使用了 ref，所以，此处需要手动来指定依赖项
  //      但是，usePersistFn 返回的函数其实就是 ref 类型的，所以，它的引用是不会改变的
  //      但是由于 useEffect 检测不到，所以，还得手动为 useEffect 指定依赖项
  useEffect(() => {
    const loadData = async () => {
      // 注意：此处需要添加 await，因为后面的代码，应该是等到请求完成后再执行
      await dispatch(persistAction())
      // 在 请求完成 后，执行某个操作
      persistAfterAction()
    }
    loadData()
  }, [dispatch, persistAction, persistAfterAction])

  return state
}

// export const useInitialState = <StateName extends keyof RootState>(
//   action: () => void,
//   stateName: StateName,
//   afterAction = () => {}
// ): RootState[StateName] => {
//   const dispatch = useDispatch()
//   const state = useSelector((state: RootState) => state[stateName])
//   // const state = useSelector<RootState, RootState[StateName]>(
//   //   state => state[stateName]
//   // )
//   // 对于 useRef 来说，参数只会在第一次组件渲染时生效，类似 useState 的参数
//   const actionRef = useRef(action)
//   // 创建用来处理 afterAction 的 ref 对象，来避免递归发送请求
//   const afterActionRef = useRef(afterAction)

//   // React 知道 useRef 创建的对象，引用不变，所以，即使在 useEffect 中
//   // 使用 useRef 对象，也不会提醒我们给 useEffect 添加依赖
//   useEffect(() => {
//     const loadData = async () => {
//       const action = actionRef.current
//       // 注意：此处需要添加 await，因为后面的代码，应该是等到请求完成后再执行
//       await dispatch(action())
//       // 在 请求完成 后，执行某个操作
//       afterActionRef.current()
//     }
//     loadData()
//   }, [dispatch])

//   return state
// }
